#ifdef  xuser
#undef  xuser
#endif

#define xuser mixc::concurrency_thread::inc
#include"concurrency/lock/atom_load.hpp"
#include"concurrency/lock/atom_store.hpp"
#include"concurrency/lock/atom_swap.hpp"
#include"concurrency/thread.hpp"
#include"concurrency/thread_self.hpp"
#include"configure/limit.hpp"
#include"configure/platform.hpp"
#include"define/base_type.hpp"
#include"macro/xdefer.hpp"
#include"macro/xmodify.hpp"
#include"macro/xthread_local.hpp"
#include"macro/xvolatile.hpp"
#include"memop/cast.hpp"
#include"utils/memory.hpp"

#if xuse_mixc_rtos
#include"extern/rtos/conf.hpp"
#include"extern/rtos/semaphore.hpp"
#include"extern/rtos/task.hpp"
#include"extern/rtos/task_conf.hpp"
#define xapi            
#define xret_t          
#elif xis_windows
#include<windows.h>
#define xapi            WINAPI
#define xret_t          DWORD{}
#elif xis_linux
#include<pthread.h>
#include<semaphore.h>
#define xapi
#define xret_t          voidp{}
#endif

namespace mixc::concurrency_thread{
#if xuse_mixc_rtos
    // pass
#else
    #ifndef xdecl_l_lambda
        #define xdecl_l_lambda
        xthread_local(l_lambda, clambda);
    #endif

    inline auto xapi thread_entry(voidp ptr){
        auto lambda                 = inc::cast<clambda>(ptr);

        // pass
        *l_lambda                   = lambda;

    #if xis_linux
        (*l_lambda)->handler(voidp(pthread_self()));
    #endif

        // windows 分离线程需要自己释放线程句柄
        // 释放 lambda
        if (lambda->invoke(); lambda.is_detached()){
        #if xis_windows
            CloseHandle(lambda->handler());
            CloseHandle(lambda->semaphore_for_suspend());
        #elif xis_linux
            sem_destroy((sem_t *)lambda->semaphore_for_suspend());
            inc::memory::free(lambda->semaphore_for_suspend(), xsizeof(sem_t));
        #else
            #error "unknown platform"
        #endif

            lambda.release();
        }
        // windows 非分离线程需要激活等待该线程退出的父线程
        // 资源释放由父线程完成
        else{
        #if xis_windows
            ReleaseSemaphore(lambda->semaphore_for_join(), 1/*给一个资源*/, nullptr);
        #else
            // linux 无需自己干预
        #endif
        }
        return xret_t;
    }

#endif
}

namespace mixc::concurrency_thread::origin{
    thread::thread(clambda && lambda) : m_lambda((clambda &&)lambda){
        xunlikely(not m_lambda.is_valid()){
            return;
        }

        // 注意：
        // is_detached 放到 if (not lambda->is_valid()){ 判定的后边，确保数据有效后在获取属性
        // 提前获取 is_detached 属性，避免 lambda 在创建的线程中释放后产生非法访问
        auto is_fail                = true;
        auto is_detached            = lambda.is_detached();

        xdefer{
            if (is_fail){
                lambda.release();

                // 设置当前失败状态
                m_lambda.im_initialize_fail();
            }
        };

    #if xuse_mixc_rtos
        static_assert(sizeof(voidp) == sizeof(inc::task));

        auto conf               = inc::task_conf{};
        conf->arg_ptr           = inc::cast<voidp>(lambda);
        conf->on_exec           = xos_event(context){
            auto & lambda       = *(clambda *)context->arg_ptr;

            if (lambda->invoke(); lambda.is_detached()){
                lambda.release();
                return;
            }

            auto sem            = inc::semaphorep(lambda->semaphore_for_join());
            auto max_task       = uxx(1024 * 1024);

            // 给足信号量，唤醒所有等待的线程
            sem->give(max_task > inc::conf::max_task_count ? max_task : inc::conf::max_task_count);
        };

        auto handler            = inc::task(conf);
        lambda->handler(inc::cast<voidp>(handler));

        (void)is_detached;
    #elif xis_windows
        if (is_detached) {
            // pass
        }
        // 这里暂时只要初值为 0，最大值为 1 就好了
        else if (lambda->semaphore_for_join(CreateSemaphoreA(nullptr/*不带名称*/, 0/*初始值*/, 1/*最大值*/, nullptr));
            lambda->semaphore_for_join() == nullptr){
            return;
        }

        // 支持多次唤醒
        if (lambda->semaphore_for_suspend(
                CreateSemaphoreA(
                    nullptr/*不带名称*/, 
                    0/*初始值*/, 
                    inc::limit::max_thread/*最大值*/, 
                    nullptr
                )
            );
            lambda->semaphore_for_suspend() == nullptr){
            CloseHandle(lambda->semaphore_for_join());
            return;
        }

        if (lambda->handler(
                CreateThread(
                    nullptr,
                    inc::limit::max_thread_stack_size, 
                    & thread_entry, 
                    inc::cast<voidp>(lambda), 
                    CREATE_SUSPENDED/*不立即运行，等待句柄设置完全*/, 
                    nullptr
                )
            );
            lambda->handler() == nullptr){

            if (not is_detached){ // 顺带释放信号量句柄
                CloseHandle(lambda->semaphore_for_join());
            }
            CloseHandle(lambda->semaphore_for_suspend());
            return;
        }
        // 由于在线程内部调用 GetCurrentThread 得到的并不是真实句柄
        // 所以等待 lambda.handler 设置完成后再唤醒子线程
        else{
            ResumeThread(lambda->handler());
        }

    #elif xis_linux
        auto conf               = pthread_attr_t{};
        auto handler            = pthread_t{};
        auto sem                = inc::memory::alloc<sem_t>();
        auto arg                = inc::cast<voidp>(lambda);

        if (sem == nullptr){
            return;
        }

        pthread_attr_init(& conf);
        pthread_attr_setdetachstate(& conf, is_detached);
        pthread_attr_setstacksize(& conf, inc::limit::max_thread_stack_size);
        sem_init(sem, 0, 0);

        // 先设置，这样在 thread 中就可以读的到
        lambda->semaphore_for_suspend(sem);

        // fail
        if (pthread_create(& handler, & conf, & thread_entry, arg) != 0){
            sem_destroy(sem);
            inc::memory::free(sem, xsizeof(pthread_mutex_t));
            return;
        }
        else{
            lambda->handler(voidp(handler));
        }

    #else
        #error "pending"
    #endif

        // 抵达这里表示初始化成功了
        // 设置 is_fail = false，指示之前的 xdefer 不再释放 lambda
        // 如果不是分离的线程，那么就需要让当前线程也指向 lambda
        is_fail                     = false;
    }

    thread::~thread(){
        if (auto h = inc::atom_swap<clambda>(xmodify(xthe.m_lambda), clambda{}); h.is_valid() and not h.is_detached()){
        #if xuse_mixc_rtos
            // 注意：禁止在关中断的场景下进行析构操作
            auto sem            = inc::semaphorep(h->semaphore_for_join());
            sem->take();
            inc::memory::free_with_destroy(sem);
        #elif xis_windows
            // 必须接收返回值，不能使用 nullptr
            DWORD ret_code = 0;

            for(WaitForSingleObject(h->semaphore_for_join(), INFINITE);
                GetExitCodeThread(h->handler(), & ret_code) == STILL_ACTIVE;){
                inc::thread_self::yield();
            }

            CloseHandle(h->handler());
            CloseHandle(h->semaphore_for_join());
            CloseHandle(h->semaphore_for_suspend());
        #elif xis_linux
            pthread_join(pthread_t(h->handler()), nullptr);
            sem_destroy((sem_t *)h->semaphore_for_suspend());
            inc::memory::free(h->semaphore_for_suspend(), xsizeof(sem_t));
        #endif

            h.release();
        }
    }

    void thread::resume(){
        inc::thread_self::resume(xthe.id());
    }
}

#undef  xapi
#undef  xret_t
